
#ifndef Velyn_Vertex_h
#define Velyn_Vertex_h

#include <iostream>

#include "Point2.h"
#include "Point3.h"
#include "Vector.h"

namespace Velyn {
    
    namespace Object {
        
        /*
         * Specifies a vertex.
         *
         * @author n7down
         */
        class Vertex {
            
        private:
            
            /*
             * Vertex position.
             */
            Point3 position;
            
            /*
             * Vertex normal.
             */
            OhioState::Math::Vector3 normal;
            
            /*
             * Vertex texture.
             */
            Point2 texture;
            
        public:
        
            /*
             * Sets a position.
             *
             * @param Takes a float value for an x, y, z that specifies the coordinates 
             * for the vertex.
             */
            void setPosition(const float x, const float y, const float z) {
                position.x = x; position.y = y; position.z = z;
            }
            
            /*
             * Sets a normal.
             *
             * @param Takes a float value for an x, y, z that specifies the unit vector
             * for a normal for a vertex.
             */
            void setNormal(const float x, const float y, const float z) {
                normal.x = x; normal.y = y; normal.z = z;
            }
      
            /*
             * Sets a texture.
             *
             * @param Takes a float value for an u and v that specifies the 
             * texture coordinates for the vertex.
             */
            void setTexture(const float u, const float v) {
                texture.u = u; texture.v = v;
            }
            
            /*
             * Gets a position.
             *
             * @return Returns a Point3 of the position of the vertex.
             */
            Point3 getPosition() {
                return position;
            }
            
            /*
             * Gets a normal.
             *
             * @return Returns a unit vector of the normal that is specified for
             * the vertex.
             */
            OhioState::Math::Vector3 getNormal() {
                return normal;
            }
            
            /*
             * Gets a texture.
             *
             * @return Returns a Point2 of the texture of the vertex.
             */
            Point2 getTexture() {
                return texture;
            }
            
            /* 
             * Interpolates a vertex with a second vertex and a weight.
             * This will create a new vertex from the original vertex and the vertex given 
             * then will return the new vertex from those values.
             *
             * This is an example of an interpolation using the vertex class:
             * v0 = [ 0 0 0 ] and v1 = [ 1 1 1 ] 
             * v3 = v0.interpolate(v1, 0.75)
             * v3 is [ 0.75 0.75 0.75 ]
             *
             * @param Takes a vertex which is the second vertex that will be interpolated 
             * and a float weight value that will specify the returned interpolated vertex 
             * between this vertex and the specified vertex.
             * @return Returns a interpolated vertex between the this vertex and the 
             * specified vertex with a given weight.
             */
            Vertex interpolate(Vertex& v, float weight) {
                Vertex result;
                
                // interpolate the position
                float px = position.x * (1 - weight) + v.position.x * weight;
                float py = position.y * (1 - weight) + v.position.y * weight;
                float pz = position.z * (1 - weight) + v.position.z * weight;
                
                // interpolate the normal
                float nx = normal.x * (1 - weight) + v.normal.x * weight;
                float ny = normal.y * (1 - weight) + v.normal.y * weight;
                float nz = normal.z * (1 - weight) + v.normal.z * weight;
                
                // interpolate the texture
                float tu = texture.u * (1 - weight) + v.texture.u * weight;
                float tv = texture.v * (1 - weight) + v.texture.v * weight;
                
                // set the result
                result.setPosition(px, py, pz);
                result.setNormal(nx, ny, nz);
                result.setTexture(tu, tv);
                
                return result;
            }
            
            /*
             * Prints of the information for the vertex.
             */
            void print() {
                std::cout << "Position: ";
                position.print();
                std::cout << "Normal: ";
                normal.print();
                std::cout << "Texture: ";
                texture.print();
            }
        };
    }
}

#endif
